/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pa036is.daoimplementation;

import cz.muni.fi.pa036is.daointerface.AddressDAO;
import cz.muni.fi.pa036is.daointerface.AdmissionDAO;
import cz.muni.fi.pa036is.daointerface.CommentDAO;
import cz.muni.fi.pa036is.daointerface.ComplaintDAO;
import cz.muni.fi.pa036is.daointerface.MatchDAO;
import cz.muni.fi.pa036is.daointerface.PersonDAO;
import cz.muni.fi.pa036is.daointerface.RoundDAO;
import cz.muni.fi.pa036is.daointerface.SeasonDAO;
import cz.muni.fi.pa036is.entity.Address;
import cz.muni.fi.pa036is.entity.Admission;
import cz.muni.fi.pa036is.entity.Comment;
import cz.muni.fi.pa036is.entity.Complaint;
import cz.muni.fi.pa036is.entity.Match;
import cz.muni.fi.pa036is.entity.Person;
import cz.muni.fi.pa036is.entity.Round;
import cz.muni.fi.pa036is.entity.Season;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.stereotype.Repository;

/**
 *
 * @author Kuba
 */
@Repository
public class PersonDAOImpl implements PersonDAO {

    private Connection con = null;
    private Statement st = null;
    private ResultSet rs = null;

    public PersonDAOImpl() throws ClassNotFoundException {



        String url = "jdbc:postgresql://localhost/PA036";
        String user = "postgres";
        String password = "test";

        try {
            Class.forName("org.postgresql.Driver");
            con = DriverManager.getConnection(url, user, password);
        } catch (SQLException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void addPerson(Person person) {
        try {

            String insert = "INSERT INTO person"
                    + "(FIRST_NAME, LAST_NAME, DATE_OF_BIRTH, PHONE_NUMBER, EMAIL) VALUES"
                    + "(?,?,?,?,?)";
            PreparedStatement preparedStatement = con.prepareStatement(insert, Statement.RETURN_GENERATED_KEYS);


            preparedStatement.setString(1, person.getFirstName());
            preparedStatement.setString(2, person.getLastName());
            preparedStatement.setDate(3, person.getDateOfBirth());
            preparedStatement.setString(4, person.getPhoneNumber());
            preparedStatement.setString(5, person.getEmail());
            preparedStatement.executeUpdate();

            ResultSet rs = preparedStatement.getGeneratedKeys();
            rs.next();
            Long personId = rs.getLong(1);
            person.setId(personId);

        } catch (SQLException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void editPerson(Person person) {
        try {

            String update = "UPDATE person SET first_name= ?, last_name= ?, date_of_birth= ?, phone_number= ?, email= ? WHERE id= ?";

            PreparedStatement preparedStatement = con.prepareStatement(update);

            preparedStatement.setString(1, person.getFirstName());
            preparedStatement.setString(2, person.getLastName());
            preparedStatement.setDate(3, person.getDateOfBirth());
            preparedStatement.setString(4, person.getPhoneNumber());
            preparedStatement.setString(5, person.getEmail());
            preparedStatement.setLong(6, person.getId());

            preparedStatement.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void deletePerson(Long id) {
        try {

            // remove admission dependencies
            AdmissionDAO admissionDAO = new AdmissionDAOImpl();
            List<Admission> admissions = admissionDAO.findAdmissionsForPerson(id);
            for (Admission a : admissions) {
                admissionDAO.deleteAdmission(a);
            }
            // remove address dependencies
            AddressDAO addressDAO = new AddressDAOImpl();
            Address address = addressDAO.getAddressByPerson(id);
            addressDAO.deleteAddress(address.getId());

            // remove matches dependencies
            MatchDAO matchDAO = new MatchDAOImpl();
            List<Match> matches = matchDAO.getAllMatchesForPerson(id);
            for (Match m : matches) {

                ComplaintDAO complaintDAO = new ComplaintDAOImpl();
                for (Complaint c : complaintDAO.getAllComplaintsForMatch(m.getId())) {
                    complaintDAO.deleteComplaint(c.getId());
                }

                RoundDAO roundDAO = new RoundDAOImpl();
                for (Round r : roundDAO.getAllRoundsForMatch(m.getId())) {
                    roundDAO.deleteRound(r.getMatchId(), r.getSequenceNumber());
                }

                CommentDAO commentDAO = new CommentDAOImpl();
                for (Comment c : commentDAO.getAllCommentsForMatch(m.getId())) {
                    commentDAO.deleteComment(c.getId());
                }
            }

            String delete = "DELETE FROM person WHERE id=?";

            PreparedStatement preparedStatement = con.prepareStatement(delete);

            preparedStatement.setLong(1, id);

            preparedStatement.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public Person findPerson(Long id) {
        Person person = new Person();
        try {

            String find = "SELECT * FROM person WHERE id=?";

            PreparedStatement preparedStatement = con.prepareStatement(find);

            preparedStatement.setLong(1, id);

            rs = preparedStatement.executeQuery();

            rs.next();
            person.setId(rs.getLong(1));
            person.setFirstName(rs.getString(2));
            person.setLastName(rs.getString(3));
            person.setDateOfBirth(rs.getDate(4));
            person.setPhoneNumber(rs.getString(5));
            person.setEmail(rs.getString(6));

        } catch (SQLException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        return person;
    }

    @Override
    public List<Person> getAllPersons() {
        List<Person> personList = new ArrayList<Person>();

        try {

            String getAll = "SELECT * FROM person";

            PreparedStatement preparedStatement = con.prepareStatement(getAll);

            rs = preparedStatement.executeQuery();

            while (rs.next()) {
                Person person = new Person();
                person.setId(rs.getLong(1));
                person.setFirstName(rs.getString(2));
                person.setLastName(rs.getString(3));
                person.setDateOfBirth(rs.getDate(4));
                person.setPhoneNumber(rs.getString(5));
                person.setEmail(rs.getString(6));
                personList.add(person);

            }
        } catch (SQLException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        return personList;
    }

    @Override
    public HashMap getPersonScoreListForSeason(Long seasonId) {

        HashMap map = new HashMap();

        // viem, ze toto je hrozny kod, no nechcelo sa mi!!!!!!!!
        try {

            SeasonDAO seasonDAO = new SeasonDAOImpl();
            Season s = seasonDAO.findSeason(seasonId);


            String getPersonsPlayedInSeason = "SELECT *\n"
                    + "FROM person p\n"
                    + "WHERE (SELECT COUNT(*) FROM match m WHERE m.player1_id = p.id OR m.player2_id = p.id AND m.season_id = ?) <> 0;";

            PreparedStatement preparedStatement = con.prepareStatement(getPersonsPlayedInSeason);
            preparedStatement.setLong(1, seasonId);

            rs = preparedStatement.executeQuery();
            MatchDAO matchDAO = new MatchDAOImpl();
            RoundDAO roundDAO = new RoundDAOImpl();

            while (rs.next()) {
                Person person = new Person();
                person.setId(rs.getLong(1));
                person.setFirstName(rs.getString(2));
                person.setLastName(rs.getString(3));
                person.setDateOfBirth(rs.getDate(4));
                person.setPhoneNumber(rs.getString(5));
                person.setEmail(rs.getString(6));

                int totalCount = 0;
                for (Match m : matchDAO.getMatchesByPersonAndSeason(person.getId(), seasonId)) {
                    if (s.getVictoryCondition() == 0) {
                        if (person.getId() == m.getPlayer1Id()) {
                            totalCount += matchDAO.getTotalPointsForPlayer1(m);
                        } else {
                            totalCount += matchDAO.getTotalPointsForPlayer2(m);
                        }
                    } else {
                        // Novy prepocet:
                        List<Round> roundsOfMach = roundDAO.getAllRoundsForMatch(m.getId());
                        if (person.getId() == m.getPlayer1Id()) { // je to player 1
                            totalCount += this.getPointsForPlayerByVictoryCondition1(roundsOfMach, 1, s);
                        } else {
                            totalCount += this.getPointsForPlayerByVictoryCondition1(roundsOfMach, 2, s);
                        }
                        
                        
//                        int player1Points = matchDAO.getTotalPointsForPlayer1(m);
//                        int player2Points = matchDAO.getTotalPointsForPlayer2(m);
//
//                        if (person.getId() == m.getPlayer1Id()) {
//                            totalCount +=
//                                    player1Points == player2Points ? s.getPointsForDraw()
//                                    : (player1Points > player2Points ? s.getPointsForWin() : s.getPointsForLose());
//                        } else {
//                            totalCount +=
//                                    player1Points == player2Points ? s.getPointsForDraw()
//                                    : (player1Points > player2Points ? s.getPointsForLose() : s.getPointsForWin());
//                        }
                    }
                }

                map.put(person, totalCount);
            }

            return map;

        } catch (SQLException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(PersonDAOImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        return map;

    }
    
    private int getPointsForPlayerByVictoryCondition1(List<Round> rounds, int player, Season season) {
        
        int winLapsCount1 = 0;
        int winLapsCount2 = 0;
        
        for (Round r: rounds) {
            
            int pts1 = r.getPointCount1();
            int pts2 = r.getPointCount2();
            
            if (pts1 == pts2) {
                continue;
            }
            
            if (pts1 > pts2) {
                winLapsCount1++;
                continue;
            }
            
            winLapsCount2++;
        }
        
        if (winLapsCount1 == winLapsCount2) {
            return season.getPointsForDraw();
        }
        
        if (player == 1) { // player 1
            
            return winLapsCount1 > winLapsCount2 ? season.getPointsForWin() : season.getPointsForLose();
        }
        
        return winLapsCount1 > winLapsCount2 ? season.getPointsForLose(): season.getPointsForWin();
    }
}
